package com.user.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.aliyun.core.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.user.dao.user.LoginDao;
import com.user.dao.user.QueryPageUser;
import com.user.dao.user.UserOrderCost;
import com.user.domain.User;
import com.user.mapper.DishMapper;
import com.user.mapper.MenberMapper;
import com.user.mapper.OrderMapper;
import com.user.mapper.UserMapper;
import com.user.service.UserService;
import com.user.utils.BaseRegexPatterns;
import com.user.utils.Constants;
import com.user.utils.R;
import com.user.utils.SendSMS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author YU
 * @Description 针对表【user】的数据库操作Service实现
 * @Date 2023-09-21 22:17:34
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Resource
    UserMapper userMapper;
    private final ObjectMapper objectMapper = new ObjectMapper();
    @Resource
    DishMapper dishMapper;
    @Resource
    OrderMapper orderMapper;
    @Resource
    MenberMapper menberMapper;


    /**
     * 发送短信
     *
     * @param phone 手机号
     * @return R
     */
    @Override
    public R sendSMS(String phone) {
        if (phone.matches(BaseRegexPatterns.EMAIL_REGEX))
            return R.ok("邮箱未完成");
        else if (phone.matches(BaseRegexPatterns.PHONE_REGEX)) {
            SendSMS sendSMS = new SendSMS();
            String s = redisTemplate.opsForValue().get(Constants.SMS_CODE_PREFIX + phone);
            if (s != null) return R.error("获取频繁");
            int code = (int) (Math.random() * 9000 + 1000);
            redisTemplate.opsForValue().set(Constants.SMS_CODE_PREFIX + phone, String.valueOf(code), 3, TimeUnit.MINUTES);
            try {
                //sendSMS.sendSms(phone, String.valueOf(code));
                System.out.println(code);
            } catch (Exception e) {
                log.error("短信服务出错");
                return R.error("发送失败");
            }
            return R.ok("短信发送成功");
        } else return R.error("格式错误");

    }

    /**
     * 登录
     *
     * @param loginDao 登录信息
     * @return R
     */
    @Override
    public R login(LoginDao loginDao) {
        String loginAcc = loginDao.getLoginAcc();
        if (StringUtils.isEmpty(loginAcc)) return R.error("登录账号不能为空");
        User user = getUserByLoginAcc(loginAcc);
        if (user == null) {
            //如果用户不存在 触发注册逻辑 判断logACC是否为手机号
            if (loginAcc.matches(BaseRegexPatterns.PHONE_REGEX)) return register(loginAcc, loginDao.getLoginPwd());
            return R.error("账号不存在");
        }
        String codePrefix = loginAcc.matches(BaseRegexPatterns.PHONE_REGEX) ? Constants.SMS_CODE_PREFIX : Constants.EMAIL_CODE_PREFIX;
        String code = redisTemplate.opsForValue().get(codePrefix + loginAcc);
        if (code == null) return R.error("请先获取验证码");
        else if (!loginDao.getLoginPwd().equals(code)) return R.error("验证码错误");
        String menber = menberMapper.selectMenberById(user.getMenberId());
        BigDecimal discount = menberMapper.selectMenberDiscountById(user.getMenberId());

        return loginSuccess(loginAcc, user.getRole(), user.getId(), discount, menber);
    }

    /**
     * 注册
     *
     * @param phone 手机号
     * @param iCode 验证码
     * @return R
     */
    public R register(String phone, String iCode) {
        if (StringUtils.isEmpty(phone)) return R.error("手机号不能为空");
        String code = redisTemplate.opsForValue().get(Constants.SMS_CODE_PREFIX + phone);
        if (code == null) return R.error("请先获取验证码");
        else if (!iCode.equals(code)) return R.error("验证码错误");
        redisTemplate.delete(Constants.SMS_CODE_PREFIX + phone);
        if (isPhoneRegistered(phone)) {
            log.error("手机号重复");
            return R.error("当前手机号重复");
        }
        User user = createUser(phone);
        user.setMenberId(1);
        save(user);
        String menber = menberMapper.selectMenberById(user.getMenberId());
        BigDecimal discount = menberMapper.selectMenberDiscountById(user.getMenberId());
        return loginSuccess(phone, user.getRole(), user.getId(), discount, menber);
    }

    /**
     * 判断手机号是否已经注册
     *
     * @param phone 手机号
     * @return boolean
     */
    public boolean isPhoneRegistered(String phone) {
        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(User::getPhone, phone);
        Integer count = baseMapper.selectCount(userWrapper);
        return count > 0;
    }

    /**
     * 创建用户
     *
     * @param phone 手机号
     * @return User
     */
    public User createUser(String phone) {
        User user = new User();
        String account = generateAccount();
        user.setAccount(account);
        user.setPhone(phone);
        user.setRole(0);
        user.setCreateTime(new Date());
        return user;
    }

    /**
     * 生成账号
     *
     * @return String
     */
    private String generateAccount() {
        String account;
        int i;
        do {
            account = Constants.ACC_CODE_PREFIX + UUID.randomUUID().toString().substring(0, 6);
            i = userMapper.selectByAcc(account);
        } while (i > 0);
        return account;
    }

    /**
     * 根据登录账号获取用户
     *
     * @param loginAcc 登录账号
     * @return User
     */
    private User getUserByLoginAcc(String loginAcc) {
        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        if (loginAcc.matches(BaseRegexPatterns.PHONE_REGEX)) userWrapper.eq(User::getPhone, loginAcc);
        else if (loginAcc.matches(BaseRegexPatterns.EMAIL_REGEX)) userWrapper.eq(User::getEmail, loginAcc);
        else userWrapper.eq(User::getAccount, loginAcc);
        User user = getOne(userWrapper);
        if (user == null) {
            user = new User();
            user.setRole(user.getRole());
        }
        return user;
    }

    /**
     * 登录成功
     *
     * @param loginAcc 登录账号
     * @return R
     */
    private R loginSuccess(String loginAcc, int role, int id, BigDecimal discount, String menber) {
        StpUtil.login(loginAcc);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", tokenInfo.getTokenValue());
        map.put("role", role);
        map.put("id", id);
        map.put("discount", discount);
        map.put("menber", menber);
        return R.ok().setData(map);

    }

    @Override
    public R getMonthCost(Integer userId) { //获取用户每月度消费
        if (userId == null) return R.error("用户id为空");
        List<UserOrderCost> userOrderCosts = userMapper.getMonthCost(userId);
        for (UserOrderCost userOrderCost : userOrderCosts) {
            String orderDetail = userOrderCost.getOrderDetail();
            try {
                Map<Integer, Integer> orderDetails = objectMapper.readValue(orderDetail, new TypeReference<Map<Integer, Integer>>() {
                });
                for (Map.Entry<Integer, Integer> entry : orderDetails.entrySet()) {
                    BigDecimal bigDecimal = dishMapper.selectMoneyById(entry.getKey());
                    userOrderCost.setCost(bigDecimal.multiply(new BigDecimal(entry.getValue())));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Map<String, BigDecimal> map = userOrderCosts.stream().collect(Collectors.groupingBy(UserOrderCost::getPaymentTime, Collectors.reducing(BigDecimal.ZERO, UserOrderCost::getCost, BigDecimal::add)));
        return R.ok().setData(map);
    }

    @Override
    public R getUser(QueryPageUser queryPageUser) {
        Page<User> mapPage = new Page<>(queryPageUser.getCurrent(), queryPageUser.getSize(), false);
        IPage<User> page = userMapper.selectUser(queryPageUser, mapPage);
        List<User> records = page.getRecords();
        page.setRecords(records);
        page.setTotal(userMapper.selectUserCount(queryPageUser));
        return R.ok().setData(page);
    }
}




